package util;

import java.util.*;

// 用户行为数据类
class UserBehavior {
    String userId;
    String itemId;
    int behaviorType;
    String userGeohash;
    String itemCategory;
    String time;

    public UserBehavior(String userId, String itemId, int behaviorType, String userGeohash, String itemCategory, String time) {
        this.userId = userId;
        this.itemId = itemId;
        this.behaviorType = behaviorType;
        this.userGeohash = userGeohash;
        this.itemCategory = itemCategory;
        this.time = time;
    }
}

// 商品信息类
class ItemInfo {
    String itemId;
    String itemGeohash;
    String itemCategory;

    public ItemInfo(String itemId, String itemGeohash, String itemCategory) {
        this.itemId = itemId;
        this.itemGeohash = itemGeohash;
        this.itemCategory = itemCategory;
    }
}

// 推荐系统类
public class RecommendationSystem {

    // 模拟用户在商品全集上的移动端行为数据
    public static List<UserBehavior> simulateUserBehaviorData(int userCount, int itemCount, int behaviorCount) {
        List<UserBehavior> userBehaviors = new ArrayList<>();
        Random random = new Random();
        for (int i = 0; i < behaviorCount; i++) {
            String userId = "user_" + random.nextInt(userCount);
            String itemId = "item_" + random.nextInt(itemCount);
            int behaviorType = random.nextInt(4) + 1;
            String userGeohash = random.nextBoolean()? "geohash_" + random.nextInt(100) : null;
            String itemCategory = "category_" + random.nextInt(10);
            String time = "2014-11-" + (random.nextInt(30) + 1) + " " + random.nextInt(24);
            userBehaviors.add(new UserBehavior(userId, itemId, behaviorType, userGeohash, itemCategory, time));
        }
        return userBehaviors;
    }

    // 模拟脱敏后的商品子集数据
    public static List<ItemInfo> simulateItemSubsetData(int itemSubsetCount, int itemCount) {
        List<ItemInfo> itemInfos = new ArrayList<>();
        Random random = new Random();
        for (int i = 0; i < itemSubsetCount; i++) {
            String itemId = "item_" + random.nextInt(itemCount);
            String itemGeohash = random.nextBoolean()? "geohash_" + random.nextInt(100) : null;
            String itemCategory = "category_" + random.nextInt(10);
            itemInfos.add(new ItemInfo(itemId, itemGeohash, itemCategory));
        }
        return itemInfos;
    }

    // 过滤出商品子集的数据
    public static List<UserBehavior> filterSubsetData(List<UserBehavior> userBehaviors, List<ItemInfo> itemInfos) {
        Set<String> itemIdSet = new HashSet<>();
        for (ItemInfo itemInfo : itemInfos) {
            itemIdSet.add(itemInfo.itemId);
        }
        List<UserBehavior> subsetData = new ArrayList<>();
        for (UserBehavior userBehavior : userBehaviors) {
            if (itemIdSet.contains(userBehavior.itemId)) {
                subsetData.add(userBehavior);
            }
        }
        return subsetData;
    }

    // 生成用户 - 商品行为矩阵
    public static Map<String, Map<String, Integer>> generateUserItemMatrix(List<UserBehavior> subsetData) {
        Map<String, Map<String, Integer>> userItemMatrix = new HashMap<>();
        // 为不同行为类型分配权重
        Map<Integer, Integer> behaviorWeights = new HashMap<>();
        behaviorWeights.put(1, 1);
        behaviorWeights.put(2, 2);
        behaviorWeights.put(3, 3);
        behaviorWeights.put(4, 4);

        for (UserBehavior userBehavior : subsetData) {
            String userId = userBehavior.userId;
            String itemId = userBehavior.itemId;
            int behaviorType = userBehavior.behaviorType;
            int weight = behaviorWeights.get(behaviorType);

            userItemMatrix.computeIfAbsent(userId, k -> new HashMap<>());
            userItemMatrix.get(userId).put(itemId, userItemMatrix.get(userId).getOrDefault(itemId, 0) + weight);
        }
        return userItemMatrix;
    }

    // 计算物品相似度矩阵
    public static Map<String, Map<String, Double>> calculateItemSimilarity(Map<String, Map<String, Integer>> userItemMatrix) {
        Map<String, Map<String, Double>> itemSimilarity = new HashMap<>();
        Map<String, Set<String>> itemUsers = new HashMap<>();

        // 统计每个物品被哪些用户交互过
        for (Map.Entry<String, Map<String, Integer>> entry : userItemMatrix.entrySet()) {
            String userId = entry.getKey();
            Map<String, Integer> userItems = entry.getValue();
            for (Map.Entry<String, Integer> itemEntry : userItems.entrySet()) {
                String itemId = itemEntry.getKey();
                itemUsers.computeIfAbsent(itemId, k -> new HashSet<>()).add(userId);
            }
        }

        // 计算物品相似度
        for (Map.Entry<String, Set<String>> item1Entry : itemUsers.entrySet()) {
            String item1 = item1Entry.getKey();
            Set<String> users1 = item1Entry.getValue();
            itemSimilarity.put(item1, new HashMap<>());
            for (Map.Entry<String, Set<String>> item2Entry : itemUsers.entrySet()) {
                String item2 = item2Entry.getKey();
                if (item1.equals(item2)) continue;
                Set<String> users2 = item2Entry.getValue();
                int intersection = 0;
                for (String user : users1) {
                    if (users2.contains(user)) {
                        intersection++;
                    }
                }
                double similarity = (double) intersection / Math.sqrt(users1.size() * users2.size());
                itemSimilarity.get(item1).put(item2, similarity);
            }
        }
        return itemSimilarity;
    }

    // 基于物品的协同过滤推荐函数
    public static List<String> recommendItemsByItemCF(String userId, Map<String, Map<String, Integer>> userItemMatrix, Map<String, Map<String, Double>> itemSimilarity, int topN) {
        Map<String, Integer> userItems = userItemMatrix.getOrDefault(userId, new HashMap<>());
        Map<String, Double> itemScores = new HashMap<>();

        for (Map.Entry<String, Integer> userItemEntry : userItems.entrySet()) {
            String itemId = userItemEntry.getKey();
            int userScore = userItemEntry.getValue();
            Map<String, Double> similarItems = itemSimilarity.get(itemId);
            if (similarItems != null) {
                for (Map.Entry<String, Double> similarItemEntry : similarItems.entrySet()) {
                    String similarItemId = similarItemEntry.getKey();
                    double similarity = similarItemEntry.getValue();
                    if (!userItems.containsKey(similarItemId)) {
                        itemScores.put(similarItemId, itemScores.getOrDefault(similarItemId, 0.0) + userScore * similarity);
                    }
                }
            }
        }

        // 按得分排序并取前 topN 个
        List<Map.Entry<String, Double>> sortedItems = new ArrayList<>(itemScores.entrySet());
        sortedItems.sort(Map.Entry.<String, Double>comparingByValue().reversed());
        List<String> recommendedItems = new ArrayList<>();
        for (int i = 0; i < Math.min(topN, sortedItems.size()); i++) {
            recommendedItems.add(sortedItems.get(i).getKey());
        }
        return recommendedItems;
    }

    // 计算用户相似度矩阵
    public static Map<String, Map<String, Double>> calculateUserSimilarity(Map<String, Map<String, Integer>> userItemMatrix) {
        Map<String, Map<String, Double>> userSimilarity = new HashMap<>();
        Map<String, Set<String>> userItems = new HashMap<>();

        // 统计每个用户交互过的物品
        for (Map.Entry<String, Map<String, Integer>> entry : userItemMatrix.entrySet()) {
            String userId = entry.getKey();
            Map<String, Integer> items = entry.getValue();
            userItems.put(userId, items.keySet());
        }

        // 计算用户相似度
        for (Map.Entry<String, Set<String>> user1Entry : userItems.entrySet()) {
            String user1 = user1Entry.getKey();
            Set<String> items1 = user1Entry.getValue();
            userSimilarity.put(user1, new HashMap<>());
            for (Map.Entry<String, Set<String>> user2Entry : userItems.entrySet()) {
                String user2 = user2Entry.getKey();
                if (user1.equals(user2)) continue;
                Set<String> items2 = user2Entry.getValue();
                int intersection = 0;
                for (String item : items1) {
                    if (items2.contains(item)) {
                        intersection++;
                    }
                }
                double similarity = (double) intersection / Math.sqrt(items1.size() * items2.size());
                userSimilarity.get(user1).put(user2, similarity);
            }
        }
        return userSimilarity;
    }

    // 基于用户的协同过滤推荐函数
    public static List<String> recommendItemsByUserCF(String userId, Map<String, Map<String, Integer>> userItemMatrix, Map<String, Map<String, Double>> userSimilarity, int topN) {
        Map<String, Integer> userItems = userItemMatrix.getOrDefault(userId, new HashMap<>());
        Map<String, Double> itemScores = new HashMap<>();

        Map<String, Double> similarUsers = userSimilarity.get(userId);
        if (similarUsers != null) {
            for (Map.Entry<String, Double> similarUserEntry : similarUsers.entrySet()) {
                String similarUserId = similarUserEntry.getKey();
                double similarity = similarUserEntry.getValue();
                Map<String, Integer> similarUserItems = userItemMatrix.get(similarUserId);
                if (similarUserItems != null) {
                    for (Map.Entry<String, Integer> itemEntry : similarUserItems.entrySet()) {
                        String itemId = itemEntry.getKey();
                        if (!userItems.containsKey(itemId)) {
                            int score = itemEntry.getValue();
                            itemScores.put(itemId, itemScores.getOrDefault(itemId, 0.0) + similarity * score);
                        }
                    }
                }
            }
        }

        // 按得分排序并取前 topN 个
        List<Map.Entry<String, Double>> sortedItems = new ArrayList<>(itemScores.entrySet());
        sortedItems.sort(Map.Entry.<String, Double>comparingByValue().reversed());
        List<String> recommendedItems = new ArrayList<>();
        for (int i = 0; i < Math.min(topN, sortedItems.size()); i++) {
            recommendedItems.add(sortedItems.get(i).getKey());
        }
        return recommendedItems;
    }

    // 逻辑回归推荐函数
    public static List<String> recommendItemsByLogisticRegression(String userId, Map<String, Map<String, Integer>> userItemMatrix, List<ItemInfo> itemInfos, int topN) {
        Random random = new Random();
        List<String> allItemIds = new ArrayList<>();
        for (ItemInfo itemInfo : itemInfos) {
            allItemIds.add(itemInfo.itemId);
        }
        Collections.shuffle(allItemIds, random);
        return allItemIds.subList(0, Math.min(topN, allItemIds.size()));
    }

    // 朴素贝叶斯推荐函数
    public static List<String> recommendItemsByNaiveBayes(String userId, Map<String, Map<String, Integer>> userItemMatrix, List<ItemInfo> itemInfos, int topN) {
        Random random = new Random();
        List<String> allItemIds = new ArrayList<>();
        for (ItemInfo itemInfo : itemInfos) {
            allItemIds.add(itemInfo.itemId);
        }
        Collections.shuffle(allItemIds, random);
        return allItemIds.subList(0, Math.min(topN, allItemIds.size()));
    }

    // 计算商品热度
    public static Map<String, Integer> calculateItemPopularity(List<UserBehavior> subsetData) {
        Map<String, Integer> itemPopularity = new HashMap<>();
        for (UserBehavior userBehavior : subsetData) {
            String itemId = userBehavior.itemId;
            itemPopularity.put(itemId, itemPopularity.getOrDefault(itemId, 0) + 1);
        }
        return itemPopularity;
    }

    // 基于热度的推荐函数
    public static List<String> recommendItemsByPopularity(String userId, Map<String, Map<String, Integer>> userItemMatrix, Map<String, Integer> itemPopularity, int topN) {
        Map<String, Integer> userItems = userItemMatrix.getOrDefault(userId, new HashMap<>());
        List<Map.Entry<String, Integer>> sortedItems = new ArrayList<>(itemPopularity.entrySet());
        sortedItems.sort(Map.Entry.<String, Integer>comparingByValue().reversed());

        List<String> recommendedItems = new ArrayList<>();
        for (Map.Entry<String, Integer> itemEntry : sortedItems) {
            String itemId = itemEntry.getKey();
            if (!userItems.containsKey(itemId)) {
                recommendedItems.add(itemId);
                if (recommendedItems.size() == topN) {
                    break;
                }
            }
        }
        return recommendedItems;
    }

    public static void main(String[] args) {
        int userCount = 20000;
        int itemCount = 1000000;
        int behaviorCount = 100000;
        int itemSubsetCount = 1000;

        List<UserBehavior> userBehaviors = simulateUserBehaviorData(userCount, itemCount, behaviorCount);
        List<ItemInfo> itemInfos = simulateItemSubsetData(itemSubsetCount, itemCount);

        // 过滤出商品子集的数据
        List<UserBehavior> subsetData = filterSubsetData(userBehaviors, itemInfos);

        // 生成用户 - 商品行为矩阵
        Map<String, Map<String, Integer>> userItemMatrix = generateUserItemMatrix(subsetData);

        // 计算物品相似度矩阵
        Map<String, Map<String, Double>> itemSimilarity = calculateItemSimilarity(userItemMatrix);

        // 计算用户相似度矩阵
        Map<String, Map<String, Double>> userSimilarity = calculateUserSimilarity(userItemMatrix);

        // 计算商品热度
        Map<String, Integer> itemPopularity = calculateItemPopularity(subsetData);

        // 生成推荐结果
        Set<String> allUserIds = userItemMatrix.keySet();
        int topN = 10;

        // 基于物品的协同过滤推荐
        System.out.println("基于物品的协同过滤推荐结果：");
        for (String userId : allUserIds) {
            List<String> recommendedItems = recommendItemsByItemCF(userId, userItemMatrix, itemSimilarity, topN);
            for (String itemId : recommendedItems) {
                System.out.println(userId + "," + itemId);
            }
        }

        // 基于用户的协同过滤推荐
        System.out.println("基于用户的协同过滤推荐结果：");
        for (String userId : allUserIds) {
            List<String> recommendedItems = recommendItemsByUserCF(userId, userItemMatrix, userSimilarity, topN);
            for (String itemId : recommendedItems) {
                System.out.println(userId + "," + itemId);
            }
        }

        // 逻辑回归推荐
        System.out.println("逻辑回归推荐结果：");
        for (String userId : allUserIds) {
            List<String> recommendedItems = recommendItemsByLogisticRegression(userId, userItemMatrix, itemInfos, topN);
            for (String itemId : recommendedItems) {
                System.out.println(userId + "," + itemId);
            }
        }

        // 朴素贝叶斯推荐
        System.out.println("朴素贝叶斯推荐结果：");
        for (String userId : allUserIds) {
            List<String> recommendedItems = recommendItemsByNaiveBayes(userId, userItemMatrix, itemInfos, topN);
            for (String itemId : recommendedItems) {
                System.out.println(userId + "," + itemId);
            }
        }

        // 基于热度的推荐
        System.out.println("基于热度的推荐结果：");
        for (String userId : allUserIds) {
            List<String> recommendedItems = recommendItemsByPopularity(userId, userItemMatrix, itemPopularity, topN);
            for (String itemId : recommendedItems) {
                System.out.println(userId + "," + itemId);
            }
        }
    }
}